/*
    Watchpost - A file monitor program for the GNOME desktop
    Copyright (C) 2006 Andrew Resch

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "callbacks.h"

void connect_callback_signals() {
	/* connect the signals in the interface */
	GtkWidget *w;
	w = glade_xml_get_widget(mainwindow_xml, "main_window");

	g_signal_connect(G_OBJECT(w), "window-state-event", G_CALLBACK(on_windowState_event), NULL);
	g_signal_connect(G_OBJECT(w), "delete-event", G_CALLBACK(on_delete_event), NULL);

	w = glade_xml_get_widget(mainwindow_xml, "add_monitor_button");
	g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(on_addMonitorButton_clicked), NULL);
	w = glade_xml_get_widget(mainwindow_xml, "help_button");
	g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(on_helpButton_clicked), NULL);
	w = glade_xml_get_widget(mainwindow_xml, "close_button");
	g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(on_closeButton_clicked), NULL);
	w = glade_xml_get_widget(mainwindow_xml, "about_button");
	g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(on_aboutButton_clicked), NULL);
	w = glade_xml_get_widget(mainwindow_xml, "monitor_view");
	g_signal_connect(G_OBJECT(w), "button-press-event", G_CALLBACK(on_monitor_list_buttonpress), NULL);
	g_signal_connect(G_OBJECT(w), "popup-menu", G_CALLBACK(on_monitor_list_popupmenu), NULL);
	w = glade_xml_get_widget(mainwindow_xml, "results_view");
	g_signal_connect(G_OBJECT(w), "button-press-event", G_CALLBACK(on_results_list_buttonpress), NULL);
	g_signal_connect(G_OBJECT(w), "popup-menu", G_CALLBACK(on_results_list_popupmenu), NULL);


	/* connect signals for filechooserdialog */
	w = glade_xml_get_widget(filechooser_xml, "file_chooser_dialog");
	g_signal_connect(G_OBJECT(w), "delete-event", G_CALLBACK(on_filechooserdialog_delete_event), NULL);
	w = glade_xml_get_widget(filechooser_xml, "file_chooser_add_button");
	g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(on_fileChooserAddButton_clicked), NULL);
	w = glade_xml_get_widget(filechooser_xml, "file_chooser_cancel_button");
	g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(on_fileChooserCancelButton_clicked), NULL);

	/* connect signals from the system tray popup menu */
	g_signal_connect(G_OBJECT(status_icon), "activate", G_CALLBACK(on_statusIcon_activate), NULL);
	g_signal_connect(G_OBJECT(status_icon), "popup-menu", G_CALLBACK(on_statusIcon_popupmenu), NULL);
	w = glade_xml_get_widget(status_icon_menu_xml, "menu_item_show");
	g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(on_showmenu_event), glade_xml_get_widget(mainwindow_xml, "main_window"));
	w = glade_xml_get_widget(status_icon_menu_xml, "menu_item_quit");
	g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(gtk_main_quit), NULL);

	/* connect signals from monitor list popup menu */
	w = glade_xml_get_widget(monitor_list_popup_xml, "menu_item_remove");
	g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(on_monitor_list_popup_remove), NULL);
	w = glade_xml_get_widget(monitor_list_popup_xml, "menu_item_clear");
	g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(on_monitor_list_popup_clear), NULL);

	/* connect signals from results list popup menu */
	w = glade_xml_get_widget(results_list_popup_xml, "menu_item_clear");
	g_signal_connect(G_OBJECT(w), "activate", G_CALLBACK(on_results_list_popup_clear), NULL);

}

/* Callback Functions */
void on_addMonitorButton_clicked(GtkWidget *widget) {
	GtkWidget *filechooser_window = glade_xml_get_widget(filechooser_xml, "file_chooser_dialog");
	gtk_dialog_run(GTK_DIALOG(filechooser_window));
	gtk_widget_hide(filechooser_window);
}
void on_fileChooserAddButton_clicked(GtkWidget *widget) {
	/* get file name from the filerchooser widget */
	GtkWidget *file_chooser = glade_xml_get_widget(filechooser_xml, "file_chooser_dialog");
	gchar *file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_chooser));

	/* check to see if a file was selected */
	if (file == NULL)
		return;

	/* check to see if this file is already being monitored */
	gpointer *lookup = g_hash_table_lookup(monitor_list_hash_table, file);
	if (lookup != NULL)
		return;

	/* get the uri for the file and add it to a GList */
	GnomeVFSURI *uri = gnome_vfs_uri_new(file);
	GList *uri_list = NULL;
	uri_list = g_list_append(uri_list, uri);
	/* we need to use the async get file info function to get the file info */
	/* the gnome vfs monitor gets started in the file_info_callback function */
	GnomeVFSAsyncHandle *file_info_handle;
	gnome_vfs_async_get_file_info(&file_info_handle, uri_list, GNOME_VFS_FILE_INFO_DEFAULT, GNOME_VFS_PRIORITY_DEFAULT, file_info_callback, NULL);
	
	/* load file icon into pixbuf */
	GdkPixbuf *pixbuf = get_file_icon(file);

	/* if the file is in the user's home directory, lets replace that path with ~ */
	file = shrink_path_with_tilde(file);
	
	/* add the icon and filename to the monitor list view */
	GtkTreeIter iter;
	gtk_list_store_append(GTK_LIST_STORE(monitor_list_list_store), &iter);
	gtk_list_store_set(GTK_LIST_STORE(monitor_list_list_store), &iter, MONITOR_LIST_COLUMN_ICON, pixbuf, MONITOR_LIST_COLUMN_NAME, file, -1);
	free(file);
	
	/* now hide the filechooserdialog */
	GtkWidget *w = glade_xml_get_widget(filechooser_xml, "file_chooser_dialog");
	gtk_widget_hide(w);

}
void file_info_callback(GnomeVFSAsyncHandle *handle, GList *results, gpointer user_data) {
	GnomeVFSMonitorType monitor_type;
	GnomeVFSGetFileInfoResult *file_info_result = (GnomeVFSGetFileInfoResult *)g_list_first(results)->data;
	if (!file_info_result)
		return;
	
	/* check if the selected uri is a file or a folder */
	GnomeVFSFileInfo *file_info = file_info_result->file_info;
	if (file_info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
		monitor_type = GNOME_VFS_MONITOR_FILE;
	}
	else if (file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
		monitor_type = GNOME_VFS_MONITOR_DIRECTORY;
	}
	/* start the gnome vfs monitor for the selected uri */
	GnomeVFSMonitorHandle *monitor_handle;
	gchar *uri_string = gnome_vfs_uri_to_string(file_info_result->uri, GNOME_VFS_URI_HIDE_NONE);

	GnomeVFSResult result = gnome_vfs_monitor_add(&monitor_handle, uri_string, monitor_type, (GnomeVFSMonitorCallback)monitor_callback, NULL);
	
	/* get the path from the uri so we can add a key in the hash table */
	gchar *path_string = watchpost_get_local_path_from_uri(uri_string);
	g_hash_table_insert(monitor_list_hash_table, (gpointer *)path_string, (gpointer *)monitor_handle);
	g_free(uri_string);

}
void on_helpButton_clicked(GtkWidget *widget) {
	GtkWidget *window = glade_xml_get_widget(mainwindow_xml, "main_window");
	GtkWidget *message_dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "There is currently no help file.\n");
	gtk_dialog_run(GTK_DIALOG(message_dialog));
	gtk_widget_hide(message_dialog);
}

void on_closeButton_clicked(GtkWidget *widget, gpointer user_data) {
	watchpost_toggle_visibility(user_data);
}

void on_aboutButton_clicked(GtkWidget *widget) {
	GtkWidget *about_window = glade_xml_get_widget(about_xml, "about_dialog");
	gtk_dialog_run(GTK_DIALOG(about_window));
	gtk_widget_hide(about_window);
}

void on_statusIcon_activate(GtkStatusIcon *status_icon, gpointer user_data) {
	GtkWidget *w = glade_xml_get_widget(mainwindow_xml, "main_window");
	watchpost_toggle_visibility(w);
}

void on_statusIcon_popupmenu(GtkStatusIcon *status_icon, guint button, guint activate_time, gpointer user_data) {
	GtkWidget *w = glade_xml_get_widget(status_icon_menu_xml, "status_icon_popup_menu");
	gtk_menu_popup (GTK_MENU(w), NULL, NULL, NULL, NULL, button, activate_time);
}

void on_windowState_event(GtkWidget *widget, GdkEventWindowState *event) {
	/* keep track of the window state */
	mainWindowState = event->new_window_state;	
}
void on_fileChooserCancelButton_clicked(GtkWidget *widget) {
	GtkWidget *w = glade_xml_get_widget(filechooser_xml, "file_chooser_dialog");
	gtk_widget_hide(w);
}
gboolean on_delete_event(GtkWidget *widget) {
	watchpost_toggle_visibility(widget);
	return TRUE;
}
gboolean on_filechooserdialog_delete_event(GtkWidget *widget) {
	gtk_widget_hide(widget);
	return TRUE;
}

void on_showmenu_event(GtkMenuItem *menuitem, gpointer user_data) {
	gtk_window_present(user_data);
	gtk_window_set_skip_taskbar_hint(user_data, FALSE);
}

void monitor_callback(GnomeVFSMonitorHandle *handle, const gchar *monitor_uri, const gchar *info_uri, GnomeVFSMonitorEventType event_type, gpointer user_data) {

	GnomeVFSURI *uri = gnome_vfs_uri_new(info_uri);
	const gchar *file_path = gnome_vfs_uri_get_path(uri);
	gchar *file = strdup(file_path);

	g_free(uri);

	/* load file icon into pixbuf */
	GdkPixbuf *pixbuf = get_file_icon(file);

	/* get event type */
	gchar *event;
	GdkPixbuf *event_icon;
	switch (event_type) {
		case GNOME_VFS_MONITOR_EVENT_CHANGED:
			event = g_malloc(strlen("Changed"));
			strcpy(event, "Changed");
			event_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), GTK_STOCK_EDIT, ICON_SIZE, 0, NULL);
		break;
		case GNOME_VFS_MONITOR_EVENT_DELETED:
			event = g_malloc(strlen("Deleted"));
			strcpy(event, "Deleted");
			event_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), GTK_STOCK_DELETE, ICON_SIZE, 0, NULL);
		break;
		case GNOME_VFS_MONITOR_EVENT_STARTEXECUTING:
			event = g_malloc(strlen("Start Executing"));
			strcpy(event, "Start Executing");
			event_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), GTK_STOCK_EXECUTE, ICON_SIZE, 0, NULL);
		break;
		case GNOME_VFS_MONITOR_EVENT_STOPEXECUTING:
			event = g_malloc(strlen("Stop Executing"));
			strcpy(event, "Stop Executing");
			event_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), GTK_STOCK_STOP, ICON_SIZE, 0, NULL);
		break;
		case GNOME_VFS_MONITOR_EVENT_CREATED:
			event = g_malloc(strlen("Created"));
			strcpy(event, "Created");
			event_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), GTK_STOCK_NEW, ICON_SIZE, 0, NULL);
		break;
		case GNOME_VFS_MONITOR_EVENT_METADATA_CHANGED:
			event = g_malloc(strlen("Metadata"));
			strcpy(event, "Metadata");
			event_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), GTK_STOCK_EDIT, ICON_SIZE, 0, NULL);
		break;
		default:
		break;
	}

	/* get time */
	time_t event_time = time(NULL);
	const char *_event_time_str = ctime(&event_time);
	char *event_time_str = g_malloc(strlen(_event_time_str));
	strncpy(event_time_str, _event_time_str, strlen(_event_time_str)-1);
	event_time_str[strlen(_event_time_str)-1] = '\0';

	/* if the file is in the user's home directory, lets replace that path with ~ */
	file = shrink_path_with_tilde(file);
	
	/* figure out if the vert slider is at the upper or lower prior to appending new row */
	GtkWidget *w = glade_xml_get_widget(mainwindow_xml, "results_view");
	GtkAdjustment *vert_adjustment = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(w));
	gboolean sticky_top = FALSE;
	gboolean sticky_bottom = FALSE;		
	if (vert_adjustment->value == 0) {
			sticky_top = TRUE;
	}
	if ((vert_adjustment->value + vert_adjustment->page_size) == vert_adjustment->upper) {
			sticky_bottom = TRUE;
	}

	/* append new row */
	GtkTreeIter iter;
	gtk_list_store_append(GTK_LIST_STORE(monitor_results_list_store), &iter);
	gtk_list_store_set(GTK_LIST_STORE(monitor_results_list_store), &iter, MONITOR_RESULTS_COLUMN_ICON, pixbuf, MONITOR_RESULTS_COLUMN_NAME, file, MONITOR_RESULTS_COLUMN_EVENT_ICON, event_icon, MONITOR_RESULTS_COLUMN_EVENT, event, MONITOR_RESULTS_COLUMN_TIME, event_time_str, -1);
	
	/* if the slider was at either extreme then stick to that edge */
	if ((sticky_top || sticky_bottom)) {
		GtkTreeIter test_iter = iter;
		GtkTreePath *path = NULL;
		if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(monitor_results_list_store), &test_iter)) {
			/* row was appended */
			if (sticky_bottom) {
				path = gtk_tree_model_get_path(GTK_TREE_MODEL(monitor_results_list_store), &iter);
			}
		}
		else {
			/* row was prepended */
			if (sticky_top) {
				path =	gtk_tree_path_new_first();
			}
		}
		if (path != NULL) {
			GtkWidget *results_view = glade_xml_get_widget(mainwindow_xml, "results_view");
			gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(results_view), path, NULL, TRUE, 1.0, 0);
			gtk_tree_path_free(path);
		}
	}
	
	/* free some memory */
	g_free(event);
	g_free(file);
	g_free(event_time_str);
}

gboolean on_monitor_list_buttonpress(GtkWidget *widget, GdkEventButton *event) {
	if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
		monitor_list_show_menu(widget, event);
		return TRUE;
	}

	return FALSE;
}

gboolean on_monitor_list_popupmenu(GtkWidget *widget) {
	monitor_list_show_menu(widget, NULL);
}

void monitor_list_show_menu(GtkWidget *widget, GdkEventButton *event) {
	GtkWidget *menu = glade_xml_get_widget(monitor_list_popup_xml, "monitor_list_popup_menu");
	
	show_popup_menu(widget, event, menu);
}

void on_monitor_list_popup_remove(GtkWidget *widget) {
	GtkWidget *tree_view = glade_xml_get_widget(mainwindow_xml, "monitor_view");
	GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
	gint num_rows = gtk_tree_selection_count_selected_rows(selection);	
	/* if no rows are selected then just return */
	if (num_rows < 1)
		return;

	/* get an iter to the selected row */
	GtkTreeIter iter;
	GtkTreeModel *tree_model = GTK_TREE_MODEL(monitor_list_list_store);
	if (!gtk_tree_selection_get_selected(selection, &tree_model, &iter))
		return;

	remove_monitor(iter);		
	
}

void on_monitor_list_popup_clear(GtkWidget *widget) {
	GtkTreeIter iter;
	GtkTreeModel *tree_model = GTK_TREE_MODEL(monitor_list_list_store);
	while (gtk_tree_model_get_iter_first(tree_model, &iter)) {
		remove_monitor(iter);
	}
}

gboolean on_results_list_buttonpress(GtkWidget *widget, GdkEventButton *event) {
	if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
		results_list_show_menu(widget, event);
		return TRUE;
	}

	return FALSE;
}

gboolean on_results_list_popupmenu(GtkWidget *widget) {
	results_list_show_menu(widget, NULL);
}

void results_list_show_menu(GtkWidget *widget, GdkEventButton *event) {
	GtkWidget *menu = glade_xml_get_widget(results_list_popup_xml, "results_list_popup_menu");
	
	show_popup_menu(widget, event, menu);
}

void on_results_list_popup_clear(GtkWidget *widget) {
	gtk_list_store_clear(monitor_results_list_store);
}

void show_popup_menu(GtkWidget *widget, GdkEventButton *event, GtkWidget *menu) {
	int button, event_time;

	if (event) {
		button = event->button;
		event_time = event->time;
	}
	else {
		button = 0;
		event_time = gtk_get_current_event_time();
	}
	
	if (!gtk_menu_get_attach_widget(GTK_MENU(menu)))
		gtk_menu_attach_to_widget(GTK_MENU(menu), widget, NULL);

	gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time);
}

void remove_monitor(GtkTreeIter iter) {
		/* get the path from the monitor list */
		gchar *path;
		gtk_tree_model_get(GTK_TREE_MODEL(monitor_list_list_store), &iter, MONITOR_LIST_COLUMN_NAME, &path, -1);
		/* expand initial tilde if any*/
		path = gnome_vfs_expand_initial_tilde(path);
		/* get the handle from the hash map and cancel the monitoring */
		gpointer *handle;
		handle = g_hash_table_lookup(monitor_list_hash_table, path);
		gnome_vfs_monitor_cancel((GnomeVFSMonitorHandle *)handle);
		g_hash_table_remove(monitor_list_hash_table, path);
		g_free(path);
	
		/* remove the row from the liststore(treemodel) */
		gtk_list_store_remove(monitor_list_list_store, &iter);
}
